/*  File Name	: DirectoryMonitor.cpp
 *  Author		: Pang Jiacai
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-10-30
 *  Description:
 */

#include "DirectoryMonitor.h"
#include "Reactor.h"
#include "EpollReactor.h"

#define NOTIFY_TO_WEB_INTERVAL 5

DirectoryMonitor* DirectoryMonitor::instance_ = NULL;

int DirectoryMonitor::RoutineTimer::handle_timeout(void)
{
	this->monitor->register_to_web();
	return 0;
}

////////////////////////////////////////////////

DirectoryMonitor::DirectoryMonitor()
{
	this->web_map_.clear();
	game_vec_.clear();
	for(int i=0;i<100;i++)
	{
		GameInfo game;
		this->game_vec_.push_back(game);
	}
}

DirectoryMonitor::~DirectoryMonitor()
{
	for(int i=0;i<(int)this->game_vec_.size();i++)
	{
		GateWayMap &map = this->game_vec_[i].svr_map;
		GateWayMap::iterator iter = map.begin();
		for (;iter != map.end();iter++)
		{
			DELETE(iter->second);
			map.erase(iter->first);
		}
	}
}
DirectoryMonitor* DirectoryMonitor::instance(void)
{
	if(instance_==NULL)
	{
		instance_ = new DirectoryMonitor();
	}
	return instance_;
}

int DirectoryMonitor::init(int line_id,int list_size,int block_size,int pool_size,
		int growth_size,std::string pool_name)
{
	super::init(list_size,block_size,pool_size,growth_size,pool_name);

	this->acceptor_ = new DircAcceptor(this);
	if(NULL==this->acceptor_)
	{
		return -1;
	}
	this->connector_ = new DircConnector(this);
	if (NULL == this->connector_)
	{
		return -1;
	}

	//request thread
	int req_thr = this->cfg()["request_thr"].asInt();
	this->create_request_thr(req_thr,"DirectoryMonitor::request",false);

	//respond thread
	int res_thr = this->cfg()["respond_thr"].asInt();
	this->create_respond_thr(res_thr,"DirectoryMonitor::respond",false);

	this->reactor(Reactor::instance());
	if(NULL==this->reactor()->implement())
	{
		this->reactor()->implement(new EpollReactor(10000,102400));
	}

	routine_timer_.monitor = this;
	routine_timer_.reactor(this->reactor());
	return 0;
}

const Json::Value &DirectoryMonitor::cfg(void)
{
#ifdef DEBUG
	return CONFIG_INSTANCE->dircserver()["debug"][0u];

#else
	return CONFIG_INSTANCE->dircserver()["online"][0u];
#endif
}

int DirectoryMonitor::start(void)
{
	super::start();

	int port = this->cfg()["port"].asInt();

	if(this->acceptor_->open(port,this->reactor())!=0)
	{
		return -1;
	}
	this->routine_timer_.schedule_timer(TimeValue(3),TimeValue(NOTIFY_TO_WEB_INTERVAL));

#ifndef DEBUG
	this->reactor()->run_reactor_loop();
	//this->wait_thread_exit();
#endif
	return 0;
}

int DirectoryMonitor::stop(void)
{
	return this->reactor()->end_reactor_loop();
}

int DirectoryMonitor::run_request_loop(void)
{
	while(true)
	{
		if(this->reactor()->run_status()==2)
		{
			LOG((INFO_LOG,"DirectoryMonitor::run_request_loop exit"));
			return 0;
		}

		MessageBlock *mb = NULL;
		this->request_mb_pop(mb);
		if (NULL != mb)
		{
			this->process_request(mb);
			this->msg_pool()->push(mb);
		}
		else
		{
			usleep(1000);
		}
	}
	return 0;
}

int DirectoryMonitor::run_respond_loop(void)
{
	while(true)
	{
		if(this->reactor()->run_status()==2)
		{
			LOG((INFO_LOG,"DirectoryMonitor::run_respond_loop exit"));
			return 0;
		}

		MessageBlock *mb = NULL;
		this->respond_mb_pop(mb);
		if(NULL!=mb)
		{
			this->process_respond(mb);
			this->msg_pool()->push(mb);
		}
		else
		{
			usleep(1000);
		}
	}
	return 0;
}

int DirectoryMonitor::process_respond(MessageBlock *mb)
{
	int svc_id =0,cmd =0;
	*mb >> svc_id>>cmd;
	LOG((DEBUG_LOG,"DirectoryMonitor::process_respond-->[cmd:%d][%d][%d]",
			cmd,svc_id,mb->data_len()));

	DirectoryService *ds = this->find_service(svc_id);
	if (NULL != ds)
	{
		int len = mb->data_len();
		mb->reset_rd_ptr();
		::memcpy(mb->base_ptr(), (char*) &len, sizeof(int));
		int send_len = ds->send_msg(mb, mb->data_len());

		LOG((DEBUG_LOG,"DirectoryMonitor::process_respond-->[%s:%d][send:%d]",
				ds->peer_addr(),ds->peer_port(),send_len));
	}
	return 0;
}

int DirectoryMonitor::process_request(MessageBlock *mb)
{
	int svc_id = 0,server=0, cmd = 0,remain=0;
	*mb >> svc_id >> server >>cmd >> remain;

	DirectoryService *ds = this->find_service(svc_id);
	if (NULL==ds)
	{
		LOG((ERROR_LOG,"DirectoryMonitor::process_request-->can't find svc"));
		return -1;
	}
	LOG((INFO_LOG,"DirectoryMonitor::process_request-->[cmd:%d][server:%d][from:%s:%d]",
			cmd,server,ds->peer_addr(),ds->peer_port()));

	switch(cmd)
	{
		case DIRCSERVER_LOGIN:
		{
			return this->gate_login(ds,mb);
		}
		case DIRCSERVER_LOGOUT:
		{
			return this->gate_logout(ds,mb);
		}
		case DIRCSERVER_UPDATE:
		{
			return this->gate_update(ds,mb);
		}
		case DIRCSERVER_GET_INFO:
		{
			return this->client_get_list(ds,mb);
		}
		default:
		{
			return 0;
		}
	}
	return 0;
}


